/*********************************************************************
	\file :           os_sw_layers\bios\gpt\Gpt.c 
	\brief:           General purpose timer.
	\author:          Omar Ramirez
	\version:         1.0
	\date:            Wed, 12, Feb 2014 
*********************************************************************/

 
#include "Gpt.h"

/********************************************************************************
* \brief Provides a single interface to configure timer channesl using the appropiate parameters.
* \param [In] ChannelConfig: 
* \param [In] Channel: 
* \return             
*/
 
static void Gpt_ConfigTimer(const PIT_ChannelConfigType* ChannelConfig, const u8* Channel);

 
void Gpt_Init(const Gpt_ConfigType* ConfigPtr)
{
    
    u8 u8ChannelsToConfig = ConfigPtr->psGptDeviceConfig->psDeviceConfig->u8NumberOfPITChannels;
    
    /* Disable PIT */
    PITCFLMT = 0;
    
    /* PIT counter freeze while in Freeze mode */
    PITCFLMT_PITFRZ        = 1u;
    
    /* Microtimer 0 Load */
    PITMTLD0 = ConfigPtr->psGptDeviceConfig->psDeviceConfig->u8MicroTimer0;
    
    /* Microtimer 1 Load */
    PITMTLD1 = ConfigPtr->psGptDeviceConfig->psDeviceConfig->u8MicroTimer1;
    
    while(u8ChannelsToConfig--) {
      Gpt_ConfigTimer(&(ConfigPtr->psGptDeviceConfig->psDeviceConfig->psChannelConfig[u8ChannelsToConfig]), &u8ChannelsToConfig);      
    }
    
    /* Access to configuration data registers for interrupts */
    INT_CFADDR               = 0x70; 	/* with vectors from 0xFF70 to 0xFF7E */ 
       
    INT_CFDATA5              = 0x06; 	/* Periodic Interrupt Timer Channel 0, S12 Core handled, priority 6 */       
}

 
void Gpt_StartTimer(Gpt_ChannelType Channel, Gpt_ValueType Value)
{
    if(0 == Mal_Pit_ChannelConfig[Channel].TimerSource) 
    {
        /* Load 8-bit microtimer load register 0 into the 8-bit micro timer down-counter 0 */
        PITCFLMT_PFLMT0     = 1u;
    } else{
        /* Load 8-bit microtimer load register 1 into the 8-bit micro timer down-counter 1 */
        PITCFLMT_PFLMT1     = 1u;
    
    }
    
    /* Channel enable */
    PITCE                 |= (u8)(1 << (Channel));
    
    /* Load 16-bit timer load register into the 16-bit timer down-counter */
    PITFLT   |= (u8)(1 << Channel);
         
     
}

 
void Gpt_StopTimer(Gpt_ChannelType Channel)
{ 
    /* Disabling channel */    
    PITCE                 &= ~(1 << (Channel));       
}

 
void Gpt_EnableNotification(Gpt_ChannelType Channel)
{
    /* Mask to enable PIT Interruption */
    u8 u8IntEnableMsk = (u8)(1 << Channel);
    
    /* Channel validator */
    
    if((Mal_Pit_DeviceConfig[0].u8NumberOfPITChannels > Channel) && (0 <= Channel)) 
    {
        /* Interrupt of PIT channel is enabled */
        PITINTE |= u8IntEnableMsk;
    }
    
    /* Enable Periodic Interrup Timer */
    PITCFLMT_PITE       = 1u;              
}

 
void Gpt_DisableNotification(Gpt_ChannelType Channel)
{
    /* Mask to enable PIT Interruption */
    u8 u8IntDisableMsk = ~(1 << Channel);
    
    /* Validating channel */
    if((Mal_Pit_DeviceConfig[0].u8NumberOfPITChannels > Channel) && (0 <= Channel)) 
    {
        /* Interrupt of PIT channel is enabled */
        PITINTE &= u8IntDisableMsk;
    }               
}

 
static void Gpt_ConfigTimer(const PIT_ChannelConfigType* ChannelConfig, const u8* Channel)
{
    /* Variable to retrieve Microtimer value */
    u16 u16MicrotimerValue;

    /* Select microtimer source for appropiate channel */
    if(ChannelConfig[*Channel].TimerSource == 0) 
    {
        /* Select microtimer source 0 */
        PITMUX &= (~(1 << (*Channel)));
    } 
    else 
    {
        /* Select microtimer source 1 */
        PITMUX |= (1 << (*Channel));
    }
    
    /* Interrupt of PIT channel is enabled */
    Gpt_EnableNotification(*Channel);
    
    /* Clear PTI interrupt flag */
    PITTF                   |= (1 << (*Channel)); 
    
    /* Retrieve Microtimer value */
    if(0 == ChannelConfig[*Channel].TimerSource) 
    {
        /* Microtimer 0 */
        u16MicrotimerValue = PITMTLD0;                 
    } else {
        /* Microtimer 1 */
        u16MicrotimerValue = PITMTLD1;          
    }
   
    /* Calculate PIT count down value */
    *((&PITLD0) + (sizeof(u16))*(*Channel)) = (u16)((((ChannelConfig[*Channel].TimeInMicroseconds) * (CNF_DESIRED_FREQ/2)) / ((u16MicrotimerValue + 1 ) * 1000)) - 1);
     
}

#pragma CODE_SEG __NEAR_SEG NON_BANKED           
 
void interrupt Gpt_Channel0_Isr(void)
{
    /* Verify that Real Time Interrupt caused the interrupt */
    if( PITTF_PTF0 == 1u )
    {
      if(NULL != Mal_Gpt_Config->psGptDeviceConfig->psDeviceConfig->psChannelConfig->CallbackFunction) 
      {
          /* Executing callback */
          Mal_Gpt_Config->psGptDeviceConfig->psDeviceConfig->psChannelConfig->CallbackFunction();    
      } 
    }
    /* Clear the real time interrupt flag */
    PITTF_PTF0 = 1u;         
}

#pragma CODE_SEG DEFAULT

/*********************************************************************
	File	: os_sw_layers\bios\gpt\Gpt.c 
*********************************************************************/
